#include "beeper.h"
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>

static const char *default_beeper_path(void)
{
    const char *p = getenv("BEEPER_EVENT_PATH");
    if (p && *p) return p;
    return "/dev/input/by-path/platform-beeper-event";
}

static int try_open(const char *path)
{
    int fd = open(path, O_WRONLY);
    return fd;
}

static int open_first_matching_event(void)
{
    // 1) by-path 下包含 beep/buzzer 的节点
    DIR *d = opendir("/dev/input/by-path");
    if (d) {
        struct dirent *e;
        while ((e = readdir(d)) != NULL) {
            if (e->d_name[0] == '.') continue;
            if (strstr(e->d_name, "beep") || strstr(e->d_name, "buzzer") || strstr(e->d_name, "pcspkr")) {
                char p[512]; snprintf(p, sizeof(p), "/dev/input/by-path/%s", e->d_name);
                int fd = try_open(p);
                if (fd >= 0) { closedir(d); return fd; }
            }
        }
        closedir(d);
    }
    // 2) 直接枚举 eventX，尝试写入 0 频率（若失败会返回 -1）
    d = opendir("/dev/input");
    if (d) {
        struct dirent *e;
        while ((e = readdir(d)) != NULL) {
            if (strncmp(e->d_name, "event", 5) == 0) {
                char p[256]; snprintf(p, sizeof(p), "/dev/input/%s", e->d_name);
                int fd = try_open(p);
                if (fd >= 0) {
                    struct input_event ev; memset(&ev, 0, sizeof(ev));
                    ev.type = EV_SND; ev.code = SND_TONE; ev.value = 0;
                    if (write(fd, &ev, sizeof(ev)) == (ssize_t)sizeof(ev)) { closedir(d); return fd; }
                    close(fd);
                }
            }
        }
        closedir(d);
    }
    return -1;
}

static int snd_tone(int fd, int freq)
{
    struct input_event ev;
    memset(&ev, 0, sizeof(ev));
    struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
    ev.time.tv_sec = ts.tv_sec; ev.time.tv_usec = ts.tv_nsec / 1000;
    ev.type = EV_SND; ev.code = SND_TONE; ev.value = freq;
    return (int)write(fd, &ev, sizeof(ev));
}

int beeper_beep(int freq_hz, int duration_ms)
{
    const char *path = default_beeper_path();
    int fd = try_open(path);
    if (fd < 0) fd = open_first_matching_event();
    if (fd < 0) { perror("open beeper"); return -1; }
    if (snd_tone(fd, freq_hz) < 0) { perror("beeper tone"); close(fd); return -1; }
    if (duration_ms > 0) usleep((useconds_t)duration_ms * 1000u);
    if (snd_tone(fd, 0) < 0) { perror("beeper off"); }
    close(fd);
    return 0;
}

int beeper_click(int duration_ms)
{
    if (duration_ms <= 0) duration_ms = 100; // default 100ms
    return beeper_beep(2000, duration_ms);
}

int beeper_off(void)
{
    const char *path = default_beeper_path();
    int fd = try_open(path);
    if (fd < 0) fd = open_first_matching_event();
    if (fd < 0) { perror("open beeper"); return -1; }
    if (snd_tone(fd, 0) < 0) { perror("beeper off"); close(fd); return -1; }
    close(fd);
    return 0;
}
